#include "Direction3D.h"
#include "Vector3D.h"
#include "../Shapes2D/Point2D.h"
#include "../Logger.h"
#include "../GameLib.h"
#include "../Str.h"
#include <math.h>

#ifndef PI
#define PI 3.141592653589793238462643383279502884
#endif

Direction3D::Direction3D(){
    set(1,0,0);
}
Direction3D::Direction3D(double i,double j,double k){
    set(i,j,k);
}
Direction3D::~Direction3D(){}
Direction3D&	Direction3D::set(double i, double j, double k){
    if (sqrt((i*i)+(j*j)+(k*k))==1)
    {
        this->i=i;
        this->j=j;
        this->k=k;
    }
	else
	{
		errLog.print("Setting the direction failed!");
	}
    return *this;
}
Direction3D&	Direction3D::rotateR(double horizontal, double vertical){
    double angleH,angleV;
    getRotationR(angleH, angleV);
    angleH+=horizontal;
    angleV+=vertical;
	setRotationR(angleH, angleV);
    return *this;
}
Direction3D&	Direction3D::setRotationR(double horizontal, double vertical){
	if (vertical> PI){vertical=PI;}
	if (vertical<=0){vertical=0.000000000000001;}
    setFromLength(cos(horizontal)*sin(vertical),sin(horizontal)*sin(vertical),cos(vertical));
	return *this;
}
Direction3D&	Direction3D::getRotationR(double &horizontal, double &vertical){
	horizontal = getRotationHorizontalR();
    vertical = getRotationVerticalR();
	return *this;
}
double			Direction3D::getRotationHorizontalR(){
	return atan2(j,i);
}
double			Direction3D::getRotationVerticalR(){
	return atan2(sqrt((j*j)+(i*i)),k);
}
double			Direction3D::getRotationHorizontalD(){
	return RAD2DEG(getRotationHorizontalR());
}
double			Direction3D::getRotationVerticalD(){
	return RAD2DEG(getRotationVerticalR());
}
Direction3D&	Direction3D::rotateD(double horizontal, double vertical){
	return rotateR(DEG2RAD(horizontal), DEG2RAD(vertical));
}
Direction3D&	Direction3D::setRotationD(double horizontal, double vertical){
	return setRotationR(DEG2RAD(horizontal), DEG2RAD(vertical));
}
Direction3D&	Direction3D::getRotationD(double &horizontal, double &vertical){
	getRotationR(horizontal, vertical);
	horizontal = RAD2DEG(horizontal);
	vertical = RAD2DEG(vertical);
	return *this;
}
Direction3D&	Direction3D::invert(){
    i*=-1;
    j*=-1;
    k*=-1;
    return *this;
}
Direction3D&	Direction3D::setFromLength(double dx,double dy,double dz){
    double total;
    total=sqrt((dx*dx)+(dy*dy)+(dz*dz));
    i=dx/total;
    j=dy/total;
    k=dz/total;
    return *this;
}
Vector3D&		Direction3D::toVector(Vector3D &vector){
    vector.set(i,j,k);
    return vector;
}
double			Direction3D::getI(){
    return i;
}
double			Direction3D::getJ(){
    return j;
}
double			Direction3D::getK(){
    return k;
}
Str&			Direction3D::toString(Str &str){
	str<<i<<"i "<<j<<"j "<<k<<"k";
	return str;
}
Direction3D&	Direction3D::copy(Direction3D &dir){
	i=dir.getI();
	k=dir.getJ();
	j=dir.getK();
	return *this;
}
Direction3D&	Direction3D::operator=(Direction3D &dir){
	return copy(dir);
}
bool			Direction3D::eq(Direction3D &dir){
	return (i==dir.getI()&&j==dir.getJ()&&k==dir.getK())?true:false;
}
bool			Direction3D::neq(Direction3D &dir){
	return !eq(dir);
}
bool			Direction3D::operator==(Direction3D &dir){
	return eq(dir);
}
bool			Direction3D::operator!=(Direction3D &dir){
	return neq(dir);
}
double			Direction3D::xyDir(){return atan2(j,i);}
double			Direction3D::xzDir(){return atan2(k,i);}
double			Direction3D::yxDir(){return atan2(i,j);}
double			Direction3D::yzDir(){return atan2(k,j);}
double			Direction3D::zxDir(){return atan2(i,k);}
double			Direction3D::zyDir(){return atan2(j,k);}
